package com.adu.miniospringbootstarter.service;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.adu.miniospringbootstarter.Entity.FileType;
import com.adu.miniospringbootstarter.config.MinioProperties;
import io.minio.*;
import io.minio.messages.Bucket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
 * minio服务类
 * @author DuZhenWen
 * @date 2021/11/08 11:08
 */
@Service
public class MinioService {

    private static MinioProperties properties;
    private static MinioClient client;

    public MinioService(MinioProperties properties) {
        this.properties=properties;
    }

    private static final Logger log = LoggerFactory.getLogger(MinioService.class);


    /**
     * 实例化minio客户端
     */
    @PostConstruct
    public void  initCleint() {
        try{
            client = MinioClient.builder()
                    .endpoint(properties.getEndpoint(),properties.getPort(),properties.isSecure())
                    .credentials(properties.getAccessKey(), properties.getSecretKey())
                    .build();
            createBucket(properties.getBucketName());
        }catch (Exception e){
            log.error(e.getStackTrace().toString());
        }
        log.info("minio初始化成功");
    }

    /**
     * 创建储存桶
     * @param name
     */
    public void createBucket(String name) {
        String bucketName=StrUtil.isEmpty(name)?properties.getBucketName():name;
        boolean exit=false;
        try{
            exit =client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        }catch (Exception e){

        }
        if(exit){
            log.info("储存器"+bucketName+"已经被创建");

        }else{
            try{
                client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }catch (Exception e){

            }
            log.info("储存器"+bucketName+"创建成功");
        }
    }

    /**
     * 上传文件，以流的形式
     */
    public static Map<String,Object> upload(MultipartFile file){
        String[] temp=file.getOriginalFilename().split("\\.");
        //文件后缀
        String suffix=temp[temp.length-1];
        // 32位随机uuid+3位类型码
        String uuid=IdUtil.simpleUUID()+ FileType.getIndexByType(suffix);

        try{
            InputStream inputStream=file.getInputStream();
            Long size=file.getSize();
            Map<String,String> metaData=new HashMap<>();
            metaData.put("filename",file.getOriginalFilename());
            metaData.put("size",Long.toString(file.getSize()/1024)+"KB");
            metaData.put("contentType",file.getContentType());
            client.putObject(
                    PutObjectArgs.builder()
                            .bucket(properties.getBucketName())
                            .object(uuid+"."+suffix)
                            .userMetadata(metaData)
                            .stream(inputStream,size,-1).build()
            );
        }catch (Exception e){
            log.info("文件上传失败"+e.getStackTrace().toString());
        }
        List<Map<String,Object>> list=new ArrayList<>();
        Map<String,Object> map=new HashMap<>();
        map.put("code",0);
        map.put("msg","success");
        // 35位uuid，后3位为文件类型码
        map.put("data",uuid);
        return map;
    }

    /**
     * 上传文件，以文件全路径为参数，不推荐使用，无法获得文件全路径
     * @param file
     * @return
     */
    public static Map<String,Object> uploadObject(String file){
        String uuid= UUID.randomUUID().toString();
        try{
            client.uploadObject(UploadObjectArgs.builder()
                    .bucket(properties.getBucketName())
                    .object(uuid)
                    .filename(file)
                    .build());
        }catch (Exception e){

        }
        Map<String,Object> map=new HashMap<>();
        map.put("code",0);
        map.put("msg","success");
        map.put("data",uuid);
        return map;
    }


    /**
     * 预览
     */
    public static Map<String,Object>  preview(String uuid){
        //获得3位文件类型码
        String typeCode=uuid.substring(32);
        String suffix="".equals(FileType.getTypeByIndex(typeCode))?"":"."+FileType.getTypeByIndex(typeCode);

        InputStream in=null;
        try{
            in=client.getObject(GetObjectArgs.builder()
                    .bucket(properties.getBucketName())
                    .object(uuid+suffix).build());
        }catch (Exception e){
            log.error("文件预览失败"+e.getStackTrace().toString());
        }

        Map<String,Object> map=new HashMap<>();
        map.put("code",0);
        map.put("msg","success");
        map.put("data",in);
        return map;
    }


    /**
     * 下载文件
     * @param uuid
     * @return
     */
    public static Map<String,Object> download(String uuid){
        //获得3位文件类型码
        String typeCode=uuid.substring(32);
        String suffix="".equals(FileType.getTypeByIndex(typeCode))?"":"."+FileType.getTypeByIndex(typeCode);
        String fileName="";
        try{
            // 获得文件原数据
            StatObjectResponse file=client.statObject(StatObjectArgs.builder()
                    .bucket(properties.getBucketName())
                    .object(uuid+suffix).build());
            // 原文件名称
            fileName=file.userMetadata().get("filename");
            InputStream in=client.getObject(GetObjectArgs.builder()
                    .bucket(properties.getBucketName())
                    .object(uuid+suffix).build());

            // 路径最后是否有\，没有的话添加
            String filePath="\\".equals(properties.getFilePath().substring(properties.getFilePath().length()-1))?properties.getFilePath():properties.getFilePath()+"\\";
            FileOutputStream out=new FileOutputStream(filePath+fileName);
            byte[] bytes=new byte[1024];
            while((in.read(bytes))!=-1){
                out.write(bytes);
            }
            out.close();
            in.close();
        }catch (Exception e){
            log.error("文件下载失败"+e.getStackTrace().toString());
        }
        Map<String,Object> map=new HashMap<>();
        map.put("code",0);
        map.put("msg","success");
        map.put("data", fileName);
        return map;
    }


    /**
     * 下载文件，写入filename中【全路径】,不推荐使用
     * @param uuid
     * @param fileName
     * @return
     */
    public static Map<String,Object> downloadObject(String uuid,String fileName){
        InputStream in=null;

        try{
            StatObjectResponse   objectStat=client.statObject(StatObjectArgs.builder()
                    .bucket(properties.getBucketName())
                    .object(uuid).build());

            client.downloadObject(DownloadObjectArgs.builder()
                    .bucket("test")
                    .object(uuid)
                    .filename(fileName).build());


        }catch (Exception e){
            log.error("文件下载失败"+e.getStackTrace().toString());
        }
        Map<String,Object> map=new HashMap<>();
        map.put("code",0);
        map.put("msg","success");
        map.put("data",null);
        return map;
    }
    /**
     * 获得储存桶bucket的信息
     * @return
     */
    public static Map<String,Object> getBucketList(){
        List<Map<String,String >> buckets=new ArrayList<>();
        try{
            List<Bucket> bucketList=client.listBuckets();
            for(Bucket bucket:bucketList){
                Map<String,String > map =new HashMap<>();
                map.put("name",bucket.name());
                DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
                map.put("createTime",bucket.creationDate().now().format(formatter).toString());
                buckets.add(map);
            }
        }catch (Exception e){
        }
        Map<String,Object> map=new HashMap<>();
        map.put("code",0);
        map.put("msg","success");
        map.put("data",buckets);
        return map;
    }

    /**
     * 删除文件
     * @param uuid
     */
    public static Map<String,Object> remove(String uuid){
        String typeCode=uuid.substring(32);
        String suffix="".equals(FileType.getTypeByIndex(typeCode))?"":"."+FileType.getTypeByIndex(typeCode);
        try{
            client.removeObject(RemoveObjectArgs.builder()
                    .bucket(properties.getBucketName())
                    .object(uuid+suffix).build());
        }catch (Exception e){
            log.error("文件删除失败"+e.getStackTrace().toString());
        }
        Map<String,Object> map=new HashMap<>();
        map.put("code",0);
        map.put("msg","success");
        map.put("data",null);
        return map;
    }

}
